package pageconfig

import (
	"fmt"
	"gioui.org/layout"
	"gioui.org/unit"
	"gioui.org/widget"
	"gioui.org/widget/material"
	"gioui.org/x/component"
	"gioui.org/x/richtext"
	"git.sr.ht/~mil/mobroute/src/apidb"
	"git.sr.ht/~mil/transito/connmobroute"
	"git.sr.ht/~mil/transito/uicomponents/divider"
	"git.sr.ht/~mil/transito/uicomponents/tableview"
	"git.sr.ht/~mil/transito/uistate"
	"git.sr.ht/~mil/transito/utillinkhandler"
	"strings"
)

type PageConfig struct {
	UIState *uistate.UIState

	TextState richtext.InteractiveText
	spans     []richtext.SpanStyle

	usesourcesCached    string
	usesourcesTextfield component.TextField
	usesourceTable      tableview.TableView
	usesourcesTableData []tableview.TableRow

	checkboxTransfersTable    widget.Bool
	checkboxTransfersComputed widget.Bool
	checkboxVerbose           widget.Bool

	searchCached    string
	searchTable     tableview.TableView
	searchTableData []tableview.TableRow
	searchTextfield component.TextField

	list widget.List
}

func Initialize(u *uistate.UIState) PageConfig {
	widget := PageConfig{
		UIState: u,

		list: widget.List{List: layout.List{Axis: layout.Vertical}},

		usesourcesTextfield: component.TextField{Editor: widget.Editor{Filter: "1234567890,"}},
		usesourcesTableData: []tableview.TableRow{},
		usesourceTable: tableview.TableView{
			Theme:  u.Theme,
			Labels: []string{"Source ID", "Provider", "Feed", "Loaded"},
		},

		searchTextfield: component.TextField{},
		searchTableData: []tableview.TableRow{},
		searchTable: tableview.TableView{
			Theme:  u.Theme,
			Labels: []string{"Source ID", "Provider", "Feed", "Loaded"},
		},
	}
	widget.usesourcesTextfield.SetText(u.Sources)
	widget.searchTextfield.SetText("paris")
	widget.checkboxTransfersTable.Value = true
	widget.checkboxTransfersComputed.Value = true

	if rendered, err := widget.UIState.MarkdownRenderer.Render([]byte(fmt.Sprintf(
		`##### Configuration
Set the use sources (CSV) and search for those sources in the below section. Ttbl/Ttcmp toggles using builtin GTFS transfers table; or computed/system generated transfers. And verbose controls the verbosity of the output.

Build: [%s](%s), [Manual](%s)`,
		truncate(Commit, 8),
		"https://git.sr.ht/~mil/transito",
		"https://git.sr.ht/~mil/transito#strongusagestrong",
	))); err == nil {
		widget.spans = rendered
	}

	return widget
}

func (widget *PageConfig) Render(gtx layout.Context) layout.Dimensions {
	utillinkhandler.HandleLinkEvents(widget.UIState.Window, &widget.TextState)

	// Update out of date search table data
	if widget.searchCached != widget.searchTextfield.Text() {
		go widget.updateSearchTable()
	}

	// Sync state out to global UIState object
	if widget.usesourcesCached != widget.UIState.Sources {
		widget.UIState.Sources = widget.usesourcesCached
	}
	widget.UIState.TransfersComputed = widget.checkboxTransfersComputed.Value
	widget.UIState.TransfersTable = widget.checkboxTransfersTable.Value
	widget.UIState.VerboseOutput = widget.checkboxVerbose.Value

	// Update out of date usesources table data
	if widget.usesourcesCached != widget.usesourcesTextfield.Text() {
		go widget.updateUsesourcesTable()
	}

	widgetCheckboxes := func(gtx layout.Context) layout.Dimensions {
		gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(40))
		gtx.Constraints.Max.Y = gtx.Constraints.Min.Y
		return layout.Flex{}.Layout(gtx, layout.Rigid(dimensionsToWidget(layout.Flex{}.Layout(
			gtx,
			layout.Flexed(0.2, material.CheckBox(widget.UIState.Theme, &widget.checkboxTransfersTable, "Ttbl").Layout),
			layout.Flexed(0.01, layout.Spacer{Width: unit.Dp(2)}.Layout),
			layout.Flexed(0.2, material.CheckBox(widget.UIState.Theme, &widget.checkboxTransfersComputed, "Tcmp").Layout),
			layout.Flexed(0.01, layout.Spacer{Width: unit.Dp(2)}.Layout),
			layout.Flexed(0.2, material.CheckBox(widget.UIState.Theme, &widget.checkboxVerbose, "Verbose").Layout),
		))))
	}

	widgetsScroll := []layout.Widget{
		// Configuration
		richtext.Text(&widget.TextState, widget.UIState.Theme.Shaper, widget.spans...).Layout,
		func(gtx layout.Context) layout.Dimensions {
			gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(15))
			widget.usesourcesTextfield.SingleLine = true
			return widget.usesourcesTextfield.Layout(gtx, widget.UIState.Theme, "Use Sources")
		},
		func(gtx layout.Context) layout.Dimensions {
			return widget.usesourceTable.Layout(gtx, widget.usesourcesTableData)
		},
		widgetCheckboxes,
		func(gtx layout.Context) layout.Dimensions {
			return divider.Divider(widget.UIState.Theme).Layout(gtx)
		},

		// Search
		material.H6(widget.UIState.Theme, "Search Sources:").Layout,
		func(gtx layout.Context) layout.Dimensions {
			gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(15))
			widget.searchTextfield.SingleLine = true
			return widget.searchTextfield.Layout(gtx, widget.UIState.Theme, "Search Sources")
		},
		func(gtx layout.Context) layout.Dimensions {
			return widget.searchTable.Layout(gtx, widget.searchTableData)
		},
	}
	return material.List(widget.UIState.Theme, &widget.list).Layout(gtx, len(widgetsScroll), func(gtx layout.Context, i int) layout.Dimensions {
		return layout.UniformInset(unit.Dp(16)).Layout(gtx, widgetsScroll[i])
	})
}

func (widget *PageConfig) updateUsesourcesTable() {
	results, _ := connmobroute.MobrouteExecuteDBStatusMDBIDs(
		widget.usesourcesTextfield.Text(),
	)
	widget.usesourcesTableData = *mapResultIntoTableResults(&results)
	widget.usesourcesCached = widget.usesourcesTextfield.Text()
}

func (widget *PageConfig) updateSearchTable() {
	results, _ := connmobroute.MobrouteExecuteDBStatusSearch(
		widget.searchTextfield.Text(),
	)
	widget.searchTableData = *mapResultIntoTableResults(&results)
	widget.searchCached = widget.searchTextfield.Text()
}

func mapResultIntoTableResults(results *[]apidb.SourceStatus) *[]tableview.TableRow {
	returnTableData := []tableview.TableRow{}
	if len(*results) > 30 {
		*results = (*results)[0:30]
	}
	for _, r := range *results {
		nonNilLocationFields := []string{}
		for _, l := range []*string{
			r.Name, r.LocationMunicipality, r.LocationSubdivision, &r.LocationCountry,
		} {
			if l != nil {
				nonNilLocationFields = append(nonNilLocationFields, *l)
			}
		}
		locationField := strings.Join(nonNilLocationFields, " / ")
		returnTableData = append(returnTableData, tableview.TableRow{
			Datum: []string{
				fmt.Sprintf("%d", r.Mdbid),
				r.Provider,
				locationField,
				fmt.Sprintf("%v", r.Loaded),
			},
		})
	}
	return &returnTableData
}
